#include "usart.h"
#include <string.h>
#include "iap_handle.h"

#if 0
#define THIS_BOARD_ID 0x05

#define SOFTWARE_VERSION    0x010000
#define BOOT_VERSION        0x010000
#define HARDWARE_VERSION    0x01


#define BOARD_ID_ADDR 0x0801E800
#define SOFTWARE_VERSION_ADDR (BOARD_ID_ADDR+4)
#define HARDWARE_VERSION_ADDR (SOFTWARE_VERSION_ADDR+4)
//bootloader版本号由bootloader程序定义，此处只给出定义的地址
#define BOOT_VERSION_ADDR 0x08002800



// uint32_t thisBoardUpgradeFlag __attribute__((section(".ARM.__at_0x0801F000")))=UPGRADE_AVAILABLE_FLAG;
uint32_t thisBoardID __attribute__((section(".ARM.__at_0x0801E800")))=THIS_BOARD_ID;
uint32_t thisBoardSoftwareVersion __attribute__((section(".ARM.__at_0x0801E804")))=SOFTWARE_VERSION;
// uint32_t thisBoardBootVersion __attribute__((section(".ARM.__at_0x0807F808")))=BOOT_VERSION;
uint32_t thisBoardHardwareVersion __attribute__((section(".ARM.__at_0x0801E808")))=HARDWARE_VERSION;
#endif

//armcc v6 warning:  
#if 0
uint32_t thisBoardID __attribute__((at(0x0801E800)))=THIS_BOARD_ID;
uint32_t thisBoardSoftwareVersion __attribute__((at(0x0801E804)))=SOFTWARE_VERSION;
uint32_t thisBoardHardwareVersion __attribute__((at(0x0801E808)))=HARDWARE_VERSION;
#endif

enum
{
    RESET_CMD=0x08,
    CTRL_CMD=0xA0,
    STATE_QUERY_CMD=0x04,
    UPGRADE_CMD=0x03,
    ENQUERY_VERSION_CMD=0x05
}COMM_CMD_t;

typedef struct
{
    //帧头
    uint8_t frame_header_h;
    uint8_t frame_header_l;
    //帧长
    uint8_t frame_len_h;
    uint8_t frame_len_l;
    //帧类别
    uint8_t frame_type;
    //数据
    uint8_t data[6];
    //crc
    uint8_t crc_h;
    uint8_t crc_l;
}rs485_frame_t;

static BIN_FILE_INFO_T stBinFileInfo = {0};
uint8_t hdwareVersion = 0;
uint32_t boot_version;
//#define FRAM_MIN (sizeof(rs485_frame_t))

uint16_t CRC16_MODBUS(unsigned char *buffer, uint16_t length)
{
    unsigned char i;
    uint16_t pos;

    uint16_t Crc_16;

    Crc_16 = 0xFFFF; // 初始值
    for ( pos = 0; pos < length; pos++) {
        Crc_16 ^= buffer[pos];
        for ( i = 8; i != 0; i--) {  // 处理每一位
            if ((Crc_16 & 0x0001) != 0) {
                Crc_16 >>= 1;
                Crc_16 ^= 0xA001;
            } else {
                Crc_16 >>= 1;
            }
        }
    }
	return  Crc_16;
}

static uint16_t pack_state_frame(uint8_t frame_type, uint8_t *out_buf)
{
    uint16_t index = 0;
	uint32_t board_id;


    //帧头
    *(out_buf+index++) = 0xff;
    *(out_buf+index++) = 0x55;
    //帧长暂时先赋0
    *(out_buf+index++) = 0x00;
    *(out_buf+index++) = 0x00;

    //命令类别
    *(out_buf+index++) = 0xB0;
    *(out_buf+index++) = frame_type;

    switch(frame_type)
    {
        //状态轮询
        case STATE_QUERY_CMD:
		{
			// BIN_FILE_INFO_T stBinFileInfo = {0};
			// uint8_t hdwareVersion = 0;
			
			// uint32_t boot_version = *(uint32_t*)BOOT_VERSION_ADDR;
			// Iap_Data_Read((uint8_t *)&stBinFileInfo, USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T));
			// Iap_Data_Read((uint8_t *)&hdwareVersion, HDWARE_VERSION_ADDR, sizeof(uint8_t));

			//目标板号
			*(out_buf+index++) = stBinFileInfo.ucBoadNo;
			//软件版本X
			*(out_buf+index++) = stBinFileInfo.ucVersionX;
			//软件版本Y
			*(out_buf+index++) = stBinFileInfo.ucVersionY;
			//软件版本Z
			*(out_buf+index++) = stBinFileInfo.ucVersionZ;
			//boot版本X
			*(out_buf+index++) = (boot_version>>16)&0xff;
			//boot版本Y
			*(out_buf+index++) = (boot_version>>8)&0xff;
			//boot版本Z
			*(out_buf+index++) = (boot_version>>0)&0xff;
			//硬件版本
			*(out_buf+index++) = hdwareVersion&0xff;
			
			#if 0
			board_id = *(uint32_t*)BOARD_ID_ADDR;
			uint32_t software_version = *(uint32_t*)SOFTWARE_VERSION_ADDR;
			uint32_t boot_version = *(uint32_t*)BOOT_VERSION_ADDR;
			uint32_t hardware_version = *(uint32_t*)HARDWARE_VERSION_ADDR;
			//附加数据
			//目标板号
			*(out_buf+index++) = board_id&0xff;
			//软件版本X
			*(out_buf+index++) = (software_version>>16)&0xff;
			//软件版本Y
			*(out_buf+index++) = (software_version>>8)&0xff;
			//软件版本Z
			*(out_buf+index++) = (software_version>>0)&0xff;
			//boot版本X
			*(out_buf+index++) = (boot_version>>16)&0xff;
			//boot版本Y
			*(out_buf+index++) = (boot_version>>8)&0xff;
			//boot版本Z
			*(out_buf+index++) = (boot_version>>0)&0xff;
			//硬件版本
			*(out_buf+index++) = hardware_version&0xff;
			#endif

			//开关机状态
			*(out_buf+index++) = open_close_flag;
			//急停状态
			*(out_buf+index++) = estop_flag;
			//拆机状态
			*(out_buf+index++) = abnormal_flag;
		}
        break;

        //取消操作指令
        case RESET_CMD:
        // *(out_buf+index++) = 0xB0;
        // *(out_buf+index++) = frame_type;
        break;

        case CTRL_CMD:
        break;

        case ENQUERY_VERSION_CMD:
        //目标板号
        *(out_buf+index++) = stBinFileInfo.ucBoadNo;
        //软件版本X
        *(out_buf+index++) = stBinFileInfo.ucVersionX;
        //软件版本Y
        *(out_buf+index++) = stBinFileInfo.ucVersionY;
        //软件版本Z
        *(out_buf+index++) = stBinFileInfo.ucVersionZ;
        //boot版本X
        *(out_buf+index++) = (boot_version>>16)&0xff;
        //boot版本Y
        *(out_buf+index++) = (boot_version>>8)&0xff;
        //boot版本Z
        *(out_buf+index++) = (boot_version>>0)&0xff;
        //硬件版本
        *(out_buf+index++) = hdwareVersion&0xff;
        break;

        case 0x02:
        break;
    }

    //帧长度
    out_buf[2] = (index>>8)&0xff;
    out_buf[3] = (index>>0)&0xff;
    
    //crc
    uint16_t crc = CRC16_MODBUS(out_buf,index);
    *(out_buf+index++) = (crc>>0)&0xff;
    *(out_buf+index++) = (crc>>8)&0xff;

    return index;
}

uint16_t rs485_tx_poll_time_count = 0;
static void rs485_tx_poll(void)
{
    static u8 state_machine = 0;

    switch(state_machine)
    {
        case 0:
        if(true == Com0.Tx_Complete)
        {
            if(RESET != usart_flag_get(USART0, USART_FLAG_TC))
            {
                // rs485_tx_poll_time_count=0;
                state_machine = 1;
            }
        }
        break;

        case 1:
        Com0.Tx_Complete = false;
        set_rs485_direction(RX);
        state_machine = 0;
        break;

        default:
        break;
    }
}

void rs485_poll(void)
{
    rs485_frame_t p = {0};
    uint16_t len;
    static bool is_upgrade_flag = false;
    uint16_t i;
    UART_FRAM_T *pstRecBuf = NULL;
    uint16_t usFramLen = 0;
    uint8_t *q = NULL;
    uint16_t usCrc16 = 0;
    static uint8_t rs485_rx_buf[255] = {0};
    static uint8_t rs485_rx_buf_index = 0;

    rs485_tx_poll();

    if(true == is_upgrade_flag)
    {
        if ((0 != vg_ucIapLoadOverFlag) || (0 != vg_ucWaitTimeOutFlag))
        {
            is_upgrade_flag = false;
        }
    }

    #if 0
    if(true == get_usart0_rx_flag())
    {
        clear_rx_flag();

        if(0 == Com0.Frame_Len)
        {
            // goto reset_rs485;
            clear_usart0_rx_buf();
            usart_interrupt_enable(USART0,USART_INT_IDLE);
            // usart_receive_config(USART0, USART_RECEIVE_ENABLE);
            return;
        }
        len = Com0.Frame_Len;
        if(len < FRAM_MIN)
        {
            goto reset_rs485;
        }
        memcpy((void*)&p,(const void*)&Com0.Rx_Buf,sizeof(rs485_frame_t));

        clear_usart0_rx_buf();
		// usart_dma_receive_config(USART0, USART_RECEIVE_DMA_ENABLE);
        usart_interrupt_enable(USART0,USART_INT_IDLE);
        

        #if 0
        if((0xff != p.frame_header_h) || (0x55 != p.frame_header_l))
        {
            return;
        }

        uint16_t frame_length = ((uint16_t)p.frame_len_h<<8)|p.frame_len_l;
        if(frame_length != (len-2))
        {
            return;
        }

       uint16_t crc_caculate = CRC16_MODBUS((unsigned char*)&p,frame_length);
       uint16_t crc_received = ((uint16_t)p.crc_l<<8)|p.crc_h;
       if(crc_caculate != crc_received)
       {
           return;
       }

       switch(p.frame_type)
       {
            //状态轮询
            case STATE_QUERY_CMD:
            //比较目标板号,0x05代表电源板
            if(THIS_BOARD_ID == p.data[0])
            {
                uint8_t send_buf[255] = {0};
                uint16_t send_len = pack_state_frame(p.frame_type ,(uint8_t*)&send_buf);
                //发送状态上报帧至主控板
                usart0_tx((uint8_t*)&send_buf,send_len);
            }
            break;

            //仅作回复，不执行任何动作
            case RESET_CMD:
            if(THIS_BOARD_ID == p.data[0])
            {
                uint8_t send_buf[255] = {0};
                uint16_t send_len = pack_state_frame(p.frame_type ,(uint8_t*)&send_buf);
                usart0_tx((uint8_t*)&send_buf,send_len);
            }
            break;

            default:
            break;
       }
       #endif
    }    
    #else
    if(true == get_usart0_rx_flag())
    {
        clear_rx_flag();

        if(Com0.Frame_Len < FRAM_MIN)
        {
            clear_usart0_rx_buf();
            // usart_interrupt_enable(USART0,USART_INT_IDLE);
            return;
        }

        #if 0
        //判断升级消息帧
        if(18 == Com0.Frame_Len)
        {
            //帧头是否符合
            if(0xFF == Com0.Rx_Buf[0] && 0x55 == Com0.Rx_Buf[1])
            {
                //帧长是否符合
                uint16_t frame_length = ((uint16_t)Com0.Rx_Buf[2]<<8)|Com0.Rx_Buf[3];
                if(frame_length == (Com0.Frame_Len-2))
                {
                    uint16_t crc_caculate = CRC16_MODBUS((unsigned char*)&Com0.Rx_Buf[0],frame_length);
                    uint16_t crc_received = ((uint16_t)Com0.Rx_Buf[17]<<8)|Com0.Rx_Buf[16];
                    //crc校验是否符合
                    if(crc_caculate == crc_received)
                    {
                        //帧类型是否符合
                        if(UPGRADE_CMD == Com0.Rx_Buf[4])
                        {
                            //是否消息帧
                            if(0x00 == Com0.Rx_Buf[5])
                            {
                                BIN_FILE_INFO_T stBinFileInfo = {0};
                                Iap_Data_Read((uint8_t *)&stBinFileInfo, USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T));

                                uint8_t board_id = stBinFileInfo.ucBoadNo;

                                //是否目标板号符合,符合则执行升级操作
                                if(board_id == Com0.Rx_Buf[6])
                                {
                                    //
                                    UartHandle_Cmd_Execute((UART_FRAM_T *)&Com0.Rx_Buf[0]);

                                    is_upgrade_flag = true;

                                    clear_usart0_rx_buf();
                                    // usart_interrupt_enable(USART0,USART_INT_IDLE);
                                    return;
                                }
                            }
                        }
                    }
                }
            }
        }
        #endif
        
        #if 0
        if(true == is_upgrade_flag)
        {
            for(i=0;i<(Com0.Frame_Len-FRAM_MIN);i++)
            {
                pstRecBuf = (UART_FRAM_T *)(Com0.Rx_Buf+i);
                if(UART_DATA_HEAD_H == pstRecBuf->ucFramHeadH && UART_DATA_HEAD_L == pstRecBuf->ucFramHeadL)
                {
                    /* 数据长度校验 */
                    usFramLen = (uint16_t)((pstRecBuf->usFramLenH << 8)| pstRecBuf->usFramLenL);
                    if ((usFramLen > DATA_MAX) || (usFramLen < 6))
                    {
                        if(usFramLen > DATA_MAX)
                        {
                            printf("error: reveided data len(%d) > DATA_MAX(%d)\r\n", usFramLen,DATA_MAX);
                        }
                        else
                        {
                            printf("error: reveived data len(%d) < 6\r\n", usFramLen);
                        }
                        continue;
                    }
                    else
                    {
                        if(usFramLen != (Com0.Frame_Len - i - 2))
                        {
                            printf("error: received data len is:%d, but parsed data len is:%d\r\n", Com0.Frame_Len, usFramLen);
                            continue;
                        }
                    }

                    q = (uint8_t*)pstRecBuf;
                    /* CRC校验 */
                    usCrc16 = CRC16_MODBUS((unsigned char*)q, usFramLen);
                    if ((((usCrc16 >> 8) & 0xff) != q[usFramLen+1+i]) || \
                        ((usCrc16 & 0xff) != q[usFramLen+i]))
                    {
                        continue;
                    }

                    //帧类型是否符合升级指令
                    if(UPGRADE_CMD != pstRecBuf->ucCmd)
                    {
                        continue;
                    }

                    UartHandle_Cmd_Execute(pstRecBuf); //指令执行

                    clear_usart0_rx_buf();
                    usart_interrupt_enable(USART0,USART_INT_IDLE);
                    return;
                }
            }


            #if 0
            //帧头是否符合
            if(0xFF == Com0.Rx_Buf[0] && 0x55 == Com0.Rx_Buf[1])
            {
                //帧长是否符合
                uint16_t frame_length = ((uint16_t)Com0.Rx_Buf[2]<<8)|Com0.Rx_Buf[3];
                if(frame_length == (Com0.Frame_Len-2))
                {
                    uint16_t crc_caculate = CRC16_MODBUS((unsigned char*)&Com0.Rx_Buf[0],frame_length);
                    uint16_t crc_received = ((uint16_t)Com0.Rx_Buf[frame_length-1]<<8)|Com0.Rx_Buf[frame_length-2];
                    //crc校验是否符合
                    if(crc_caculate == crc_received)
                    {
                        //帧类型是否符合
                        if(UPGRADE_CMD == Com0.Rx_Buf[4])
                        {
                            //是否文件数据帧
                            if(0x00 != Com0.Rx_Buf[5])
                            {
                                //是否目标板号符合,符合则执行升级操作
                                uint32_t board_id = *(uint32_t*)BOARD_ID_ADDR;
                                if(board_id == Com0.Rx_Buf[6])
                                {
                                    UartHandle_Cmd_Execute((UART_FRAM_T *)&Com0.Rx_Buf[0]);
                                }
                            }
                        }
                        //如果升级时收到了其他帧，则不执行升级操作
                        else if(UPGRADE_CMD == Com0.Rx_Buf[4])
                        {

                        }
                    }
                }
            }
            #endif
        }
        #endif

        rs485_frame_t *tmp = NULL;
        for(i=0;i<(Com0.Frame_Len-6);i++)
        {
            tmp = (rs485_frame_t *)(Com0.Rx_Buf+i);
            if((0xff == tmp->frame_header_h) && (0x55 == tmp->frame_header_l))
            {
                break;
            }
            else
            {
                tmp = NULL;
            }
        }

        if(NULL == tmp)
        {
            printf("could not find frame header\r\n");

            printf("original data is:\r\n");
            for(i=0;i<Com0.Frame_Len;i++)
            {
                printf("%02X ",Com0.Rx_Buf[i]);
            }
            printf("\r\n");
            return;
        }

        memcpy((void*)&p,(const void*)tmp,sizeof(rs485_frame_t));
        // memcpy((void*)&p,(const void*)Com0.Rx_Buf,sizeof(rs485_frame_t));
        len = Com0.Frame_Len;
		clear_usart0_rx_buf();
		// usart_interrupt_enable(USART0,USART_INT_IDLE);

        if(stBinFileInfo.ucBoadNo != p.data[0])
        {
            return;
        }

        //接收数据包不完整的情形，将接受的数据暂时存放于rs485_rx_buf中，待下次接收数据时，将rs485_rx_buf中的数据与本次接收的数据进行拼接，再处理
        uint16_t frame_length = ((uint16_t)p.frame_len_h<<8)|p.frame_len_l;
        if(frame_length != (len-2))
        {
            printf("received frame is not match, frame length is:%d, but received length is:%d\r\n",frame_length,len-2);

            //接收数据帧小于协议规定的长度，说明接收数据不完整
            if((frame_length > (len-2)) && (p.frame_type != 0x04))
            {
                printf("received frame is not complete\r\n");
                return;
            }

            // for(uint8_t i=0;i<len;i++)
            // {
            //     rs485_rx_buf[rs485_rx_buf_index++] = Com0.Rx_Buf[i];
            //     if(rs485_rx_buf_index >= 255)
            //     {
            //         rs485_rx_buf_index = 0;
            //     }
            // }

            // //新增了接收数据站不完整的帧处理
            // rs485_frame_t* q = (rs485_frame_t*)rs485_rx_buf;

            // if(p.frame_type != 0x04)
            // {
            //     return;
            // }
        }


        // if((0xff != p.frame_header_h) || (0x55 != p.frame_header_l))
        // {
        //     printf("frame header is not correct\n");
        //     return;
        // }

       uint16_t crc_caculate = CRC16_MODBUS((unsigned char*)&p,frame_length);
       uint16_t crc_received = ((uint16_t)p.crc_l<<8)|p.crc_h;
       if(crc_caculate != crc_received)
       {
            if((p.frame_type != STATE_QUERY_CMD) && (p.frame_type != ENQUERY_VERSION_CMD))
            {
                printf("frame crc is not matched,crc_caculate:%04X,crc_received:%04X\n",crc_caculate,crc_received);
                return;
            }
       }

    //    BIN_FILE_INFO_T stBinFileInfo = {0};
    //    Iap_Data_Read((uint8_t *)&stBinFileInfo, USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T));

       switch(p.frame_type)
       {
            //状态轮询
            case STATE_QUERY_CMD:
            //比较目标板号,0x05代表电源板
            // if(stBinFileInfo.ucBoadNo == p.data[0])
            {
                //addred by y.fan on 2025.04.03，主控板下发的状态轮询帧中增加了运动部件是否安全标志，0x00表示不安全，0x01表示安全
                is_motion_part_safe = p.data[1];
                if((SYS_STANDBY_STATE == sys_state)&&(0x01 == is_motion_part_safe))
                {
                    //如果当前运动部件安全，则可以待机
                    stby_relay_off();
                }

                uint8_t send_buf[255] = {0};
                uint16_t send_len = pack_state_frame(p.frame_type ,(uint8_t*)&send_buf);
                //发送状态上报帧至主控板
                usart0_tx((uint8_t*)&send_buf,send_len);
            }
            break;

            //仅作回复，不执行任何动作
            case RESET_CMD:
            // if(stBinFileInfo.ucBoadNo == p.data[0])
            {
                uint8_t send_buf[255] = {0};
                uint16_t send_len = pack_state_frame(p.frame_type ,(uint8_t*)&send_buf);
                usart0_tx((uint8_t*)&send_buf,send_len);
            }
            break;

            case CTRL_CMD:
            //远程待机控制指令
            if(0xA1 == p.data[0])
            {
                //待机
                if(p.data[3] == 0x01)
                {
                    sys_state = SYS_STANDBY_STATE;
                }
                //开机
                else if(p.data[3] == 0x02)
                {
                    sys_state = SYS_NORMAL_STATE;
                }
            }

            //清除拆机标志指令
            if(0xA2 == p.data[0])
            {
                if(0xFA == abnormal_flag)
                {
                    record_broken_event(0x00);
                    abnormal_flag = read_broken_event();
                }
            }

            if((0xA1 == p.data[0]) || (0xA2 == p.data[0]))
            {
                uint8_t send_buf[255] = {0};
                uint16_t send_len = pack_state_frame(p.frame_type ,(uint8_t*)&send_buf);
                usart0_tx((uint8_t*)&send_buf,send_len);
            }
            break;

            case ENQUERY_VERSION_CMD:
            {
                uint8_t send_buf[255] = {0};
                uint16_t send_len = pack_state_frame(p.frame_type ,(uint8_t*)&send_buf);
                usart0_tx((uint8_t*)&send_buf,send_len);
            }
            break;

            default:
            break;
       }
    }
		

    #endif
}



void UartHandle_RecAndOperate(void)
{

}


void PrintBoardInfo(void)
{
    // BIN_FILE_INFO_T stBinFileInfo = {0};
    // uint8_t hdwareVersion = 0;
    boot_version = *(uint32_t*)BOOT_VERSION_ADDR;
    Iap_Data_Read((uint8_t *)&stBinFileInfo, USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T));
    Iap_Data_Read((uint8_t *)&hdwareVersion, HDWARE_VERSION_ADDR, sizeof(uint8_t));

    printf("*************************************\n");
    printf("this board id is:%d\n",stBinFileInfo.ucBoadNo);
    printf("this board hardware version is:V%02d\n",hdwareVersion);
    printf("this board boot version is: %02x.%02x.%02x\n",(boot_version>>16)&0xff,(boot_version>>8)&0xff,boot_version&0xff);
    printf("this board software version is: %02d.%02d.%02d\n",stBinFileInfo.ucVersionX,stBinFileInfo.ucVersionY,stBinFileInfo.ucVersionZ);
    printf("*************************************\n");
}



